/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package yuhuibear.poat.object.bean;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import yuhuibear.poat.annotations.relation.Field;
import yuhuibear.poat.exception.PoatException;
import yuhuibear.poat.util.NameConvertor;

/**
 * 描述bean 字段的实体类.
 * 
 * @author yuhuibear
 */
public class AttributeMapper {

	/**
	 * 数据库中对应的列名
	 */
	private String dbName;

	/**
	 * 该字段的属性名
	 */
	private String name;

	/**
	 * 映射器对应的属性的类型。
	 */
	private Class<?> attributeType;

	/**
	 * bean 中 setter
	 */
	private Method setter;

	/**
	 * bean 中 getter
	 */
	private Method getter;

	private Map<Class<?>, Annotation> annotations;

	public AttributeMapper() {
		setter = null;
		this.annotations = new HashMap<Class<?>, Annotation>();
	}

	public AttributeMapper(String name, int col, Method mthd) {
		this.name = name;
		setter = mthd;
		this.annotations = new HashMap<Class<?>, Annotation>();
	}

	/**
	 * 设置指定对象的属性值。
	 * 
	 * @param obj
	 * @param value
	 * @return
	 * @throws java.lang.Exception
	 */
	public Object setValue(Object obj, Object value) throws Exception {
		try {
			if (value == null && attributeType.isPrimitive())
				return obj;
			return this.setter.invoke(obj, convert(value));
		} catch (java.lang.IllegalArgumentException iae) {
			String msg = setter.getName() + ", needs: " + setter.getParameterTypes()[0].getName() + ", type of args : "
					+ (value == null ? "null" : value.getClass().toString());
			throw new PoatException(msg, iae);
		}
	}

	private static final Class<?> intClaz = new Integer[0].getClass();

	private static final Class<?> longClaz = new Long[0].getClass();

	private static final Class<?> doubleClaz = new Double[0].getClass();

	protected Object convert(Object obj) throws Exception {
		if (obj == null)
			return obj;
		Class<?> objType = obj.getClass();
		if (objType.equals(BigDecimal.class) && attributeType.equals(Double.class))
			return BigDecimal.class.cast(obj).doubleValue();
		else if (objType.equals(BigInteger.class) && attributeType.equals(Long.class))
			return BigInteger.class.cast(obj).longValue();
		else if (java.sql.Array.class.isAssignableFrom(objType)) {
			String str = obj.toString();
			String[] elm = str.substring(1, str.length() - 1).split(",");
			List<Object> lst = new LinkedList<Object>();
			if (attributeType.equals(intClaz)) {
				for (String e : elm)
					lst.add(Integer.parseInt(e.trim()));
				return lst.toArray(new Integer[0]);
			} else if (attributeType.equals(longClaz)) {
				for (String e : elm)
					lst.add(Long.parseLong(e.trim()));
				return lst.toArray(new Long[0]);
			} else if (attributeType.equals(doubleClaz)) {
				for (String e : elm)
					lst.add(Double.parseDouble(e.trim()));
				return lst.toArray(new Double[0]);
			}
		}
		return obj;
	}

	/**
	 * 取出该类型的该属性值。
	 * 
	 * @param obj
	 * @return
	 * @throws java.lang.Exception
	 */
	public Object getValue(Object obj) throws Exception {
		Object value = this.getter.invoke(obj);
		return value;
	}

	/**
	 * 判断是否有该标签
	 * 
	 * @param type
	 * @return
	 */
	public boolean hasAnnotation(Class<? extends Annotation> type) {

		return this.annotations.containsKey(type);
	}

	/**
	 * 获取该类上的标签
	 * 
	 * @param <T>
	 * @param type
	 * @return
	 */
	public <T extends Annotation> T getAnnotation(Class<T> type) {
		Annotation an = this.annotations.get(type);
		return type.cast(an);
	}

	public void addAnnotation(Class<? extends Annotation> type, Annotation ant) {
		this.annotations.put(type, ant);
	}

	public void addAnnotation(Annotation[] ans) {
		for (Annotation cAn : ans) {
			this.annotations.put(cAn.annotationType(), cAn);
		}
	}

	/**
	 * 获取当前属性的数据库名称， 如果该名称没有被数据库定义标签指定， 则有当前属性名转换而来。
	 * 
	 * @return
	 */
	public String getDBName() {
		if (this.dbName == null) {
			Field atr = (Field) this.annotations.get(Field.class);
			if (atr != null) {
				this.dbName = atr.name().trim();
			} else {
				this.dbName = NameConvertor.toTableName(name);
			}
		}
		return this.dbName;
	}

	public Class<?> getAttributeType() {
		return attributeType;
	}

	public void setAttributeType(Class<?> attributeType) {
		this.attributeType = attributeType;
	}

	public Method getSetter() {
		return setter;
	}

	public void setSetter(Method setter) {
		this.setter = setter;
	}

	public Method getGetter() {
		return getter;
	}

	public void setGetter(Method getter) {
		this.getter = getter;
	}

	public Map<Class<?>, Annotation> getAnnotations() {
		return annotations;
	}

	public void setAnnotations(Map<Class<?>, Annotation> annotations) {
		this.annotations = annotations;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
